package evolutionaryballoons.visual;

import static evolutionaryballoons.Configuration.sHeight;
import static evolutionaryballoons.Configuration.sNumberOfCurrents;
import static evolutionaryballoons.Configuration.sWidth;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Point2D;
import java.util.LinkedList;
import java.util.List;

import evolutionaryballoons.Balloon;
import evolutionaryballoons.Currents;
import evolutionaryballoons.Points;

public class WorldView extends Component {
	private static final long serialVersionUID = -4607036703070166998L;
	private static int sBalloonRadius = 10;
	private static int sPointRadius = 6;
	
	private static Color sColorOfSky = new Color(0.8f, 0.9f, 1.0f);
	private static Color sColorOfMarkers1 = sColorOfSky.darker();
	private static Color sColorOfMarkers2 = Color.BLACK;
	private static Color sColorOfPoints = sColorOfMarkers1;
	private static Color sColorOfClosestPoint = Color.BLUE;
	private static Color sColorOfBalloonBurnerOn = Color.RED;
	private static Color sColorOfBalloonBurnerOff = Color.RED.darker();
	
	private static int sRepaintBalloonSize = 3 * sBalloonRadius;
	private static int sRepaintPointSize = 2 * sPointRadius;
	
	private Currents currents;
	private Balloon balloon;
	private Points points;
	
	private Point2D oldTargetPoint;
	private List<Point2D> tracer;
	
	public WorldView(Currents currents, Balloon balloon, Points points) {
		this.currents = currents;
		this.balloon = balloon;
		this.points = points;
		this.setPreferredSize(new Dimension(sWidth, sHeight));
		this.tracer = new LinkedList<Point2D>();
	}
	
	public void paint(Graphics g) {
		// Draw Sky
		
		g.setColor(sColorOfSky);
		g.fillRect(0, 0, sWidth, sHeight);
		
		// Draw Currents
		
		for (int i = 0; i < sNumberOfCurrents; i++) {
			int y = i * sHeight / sNumberOfCurrents;
			
			Graphics2D g2d = (Graphics2D) g;
			g2d.setStroke(new BasicStroke(1));
			g.setColor(sColorOfMarkers1);
			g.drawLine(0, y, sWidth, y);
			
			// Draw Arrow
			
			int w = 15;
			int y2 = (int) ((i + 0.5) * sHeight / sNumberOfCurrents);
			g2d.setStroke(new BasicStroke(5));
			g.drawLine(sWidth - 20 - w, y2, sWidth - 20 + w, y2);
			
			w = (int) (currents.get(i) * 15);
			g.setColor(sColorOfMarkers2);
			g.drawLine(sWidth - 20, y2, sWidth - 20 + w, y2);
			
			g2d.setStroke(new BasicStroke(1));
			g.drawLine(sWidth - 20, y2 - 5, sWidth - 20, y2 + 5);
			g.drawLine(sWidth - 20 + w, y2 - 5, sWidth - 20 + w, y2 + 5);
		}
		
		// Draw Tracer
		
		synchronized (tracer) {
			if (tracer.size() > 0) {
				g.setColor(sColorOfMarkers1);
				Point2D p1 = tracer.get(0);
				for (Point2D p2: tracer) {
					g.drawLine((int) p1.getX(), (int) p1.getY(), (int) p2.getX(), (int) p2.getY());
					
					p1 = p2;
				}
			}
		}
		
		// Draw Points
		for (Point2D p: points.getAll()) {
			g.setColor(sColorOfPoints);
			g.fillOval((int) p.getX() - sPointRadius, 
					(int) p.getY() - sPointRadius, 
					2 * sPointRadius, 2 * sPointRadius);
		}
		
		// Targetted Point
		
		Point2D p = points.get(balloon.targetPoint);
		if (p != null) {
			g.setColor(sColorOfClosestPoint);
			g.fillOval((int) p.getX() - sPointRadius, 
					(int) p.getY() - sPointRadius, 
					2 * sPointRadius, 2 * sPointRadius);
		}
		
		// Draw Balloon
		
		g.setColor(balloon.burnerOn ? sColorOfBalloonBurnerOn : sColorOfBalloonBurnerOff);
		g.fillOval((int) balloon.x - sBalloonRadius, 
				(int) balloon.y - sBalloonRadius, 
				2 * sBalloonRadius, 2 * sBalloonRadius);
	}

	public void mark() {
		synchronized (tracer) {
			tracer.add(new Point2D.Double(balloon.x, balloon.y));
		}
	}

	public void draw() {
		// Redraw target points?
		
		Point2D targetPoint = points.get(balloon.targetPoint);
		if (oldTargetPoint != targetPoint) {
			if (oldTargetPoint != null) {
				this.repaint((int) oldTargetPoint.getX() - sRepaintPointSize, 
						(int) oldTargetPoint.getY() - sRepaintPointSize, 
						sRepaintPointSize * 2, sRepaintPointSize * 2);
			}
			
			if (targetPoint != null) {
				this.repaint((int) targetPoint.getX() - sRepaintPointSize, 
						(int) targetPoint.getY() - sRepaintPointSize, 
						sRepaintPointSize * 2, sRepaintPointSize * 2);
			}
			
			oldTargetPoint = targetPoint;
		}
		
		// Redraw balloon

		this.repaint((int) balloon.x - sRepaintBalloonSize, 
				(int) balloon.y - sRepaintBalloonSize, 
				sRepaintBalloonSize * 2, sRepaintBalloonSize * 2);
	}
}
